package memory

import (
	"context"
	"fmt"
	"sync"
	"time"
)

// BaseMemoryManager provides a base implementation of MemoryManager
type BaseMemoryManager struct {
	store  MemoryStore
	config *MemoryConfig
	stats  *MemoryStats
	mu     sync.RWMutex
}

// Initialize implements MemoryManager
func (m *BaseMemoryManager) Initialize(ctx context.Context) error {
	return nil
}

// Close implements MemoryManager
func (m *BaseMemoryManager) Close() error {
	return nil
}

// Store implements MemoryManager
func (m *BaseMemoryManager) Store(ctx context.Context, memory *MemoryEntry) error {
	start := time.Now()
	err := m.store.Store(ctx, memory)
	if err == nil {
		m.updateStats(memory, time.Since(start))
	}
	return err
}

// Get implements MemoryManager
func (m *BaseMemoryManager) Get(ctx context.Context, id string) (*MemoryEntry, error) {
	start := time.Now()
	memory, err := m.store.Get(ctx, id)
	if err == nil {
		m.updateLatency(time.Since(start))
	}
	return memory, err
}

// Search implements MemoryManager
func (m *BaseMemoryManager) Search(ctx context.Context, query string, limit int) ([]*MemoryEntry, error) {
	start := time.Now()
	memories, err := m.store.Search(ctx, query, limit)
	if err == nil {
		m.updateLatency(time.Since(start))
	}
	return memories, err
}

// SearchByEmbedding implements MemoryManager
func (m *BaseMemoryManager) SearchByEmbedding(ctx context.Context, embedding []float32, limit int) ([]*MemoryEntry, error) {
	return nil, fmt.Errorf("vector similarity search not implemented")
}

// List implements MemoryManager
func (m *BaseMemoryManager) List(ctx context.Context, filters map[string]interface{}, limit int) ([]*MemoryEntry, error) {
	return m.Search(ctx, "", limit)
}

// ListByType implements MemoryManager
func (m *BaseMemoryManager) ListByType(ctx context.Context, memoryType MemoryType, limit int) ([]*MemoryEntry, error) {
	start := time.Now()
	memories, err := m.store.ListByType(ctx, memoryType, limit)
	if err == nil {
		m.updateLatency(time.Since(start))
	}
	return memories, err
}

// Delete implements MemoryManager
func (m *BaseMemoryManager) Delete(ctx context.Context, id string) error {
	return m.store.Delete(ctx, id)
}

// Clear implements MemoryManager
func (m *BaseMemoryManager) Clear(ctx context.Context) error {
	m.resetStats()
	return m.store.Clear(ctx)
}

// GetByTags implements MemoryManager
func (m *BaseMemoryManager) GetByTags(ctx context.Context, tags []string) ([]*MemoryEntry, error) {
	memories, err := m.Search(ctx, "", 100) // Get all memories and filter by tags
	if err != nil {
		return nil, err
	}

	var result []*MemoryEntry
	for _, memory := range memories {
		if hasAllTags(memory.Tags, tags) {
			result = append(result, memory)
		}
	}
	return result, nil
}

// GetByTimeRange implements MemoryManager
func (m *BaseMemoryManager) GetByTimeRange(ctx context.Context, start, end time.Time) ([]*MemoryEntry, error) {
	memories, err := m.Search(ctx, "", 100) // Get all memories and filter by time
	if err != nil {
		return nil, err
	}

	var result []*MemoryEntry
	for _, memory := range memories {
		if memory.CreatedAt.After(start) && memory.CreatedAt.Before(end) {
			result = append(result, memory)
		}
	}
	return result, nil
}

// UpdateTags implements MemoryManager
func (m *BaseMemoryManager) UpdateTags(ctx context.Context, id string, tags []string) error {
	memory, err := m.Get(ctx, id)
	if err != nil {
		return err
	}

	memory.Tags = tags
	memory.UpdatedAt = time.Now()
	return m.Store(ctx, memory)
}

// GetStats implements MemoryManager
func (m *BaseMemoryManager) GetStats() (*MemoryStats, error) {
	m.mu.RLock()
	defer m.mu.RUnlock()
	return m.stats, nil
}

// GetRelevantMemories implements MemoryManager
func (m *BaseMemoryManager) GetRelevantMemories(ctx context.Context, query string, limit int, minSimilarity float32) ([]*MemoryEntry, error) {
	memories, err := m.Search(ctx, query, limit)
	if err != nil {
		return nil, err
	}
	return memories, nil
}

// AddToShortTerm implements MemoryManager
func (m *BaseMemoryManager) AddToShortTerm(ctx context.Context, memory *MemoryEntry) error {
	memory.Type = MemoryTypeShortTerm
	return m.Store(ctx, memory)
}

// AddToLongTerm implements MemoryManager
func (m *BaseMemoryManager) AddToLongTerm(ctx context.Context, memory *MemoryEntry) error {
	memory.Type = MemoryTypeLongTerm
	return m.Store(ctx, memory)
}

// Helper methods

func (m *BaseMemoryManager) updateStats(memory *MemoryEntry, duration time.Duration) {
	m.mu.Lock()
	defer m.mu.Unlock()

	m.stats.TotalCount++
	m.stats.TypeCounts[memory.Type]++
	m.updateLatency(duration)
}

func (m *BaseMemoryManager) updateLatency(duration time.Duration) {
	m.mu.Lock()
	defer m.mu.Unlock()

	if m.stats.AverageLatency == 0 {
		m.stats.AverageLatency = duration
	} else {
		m.stats.AverageLatency = (m.stats.AverageLatency + duration) / 2
	}
}

func (m *BaseMemoryManager) resetStats() {
	m.mu.Lock()
	defer m.mu.Unlock()

	m.stats = &MemoryStats{
		TypeCounts: make(map[MemoryType]int64),
	}
}

func hasAllTags(memoryTags, searchTags []string) bool {
	if len(searchTags) == 0 {
		return true
	}
	if len(memoryTags) < len(searchTags) {
		return false
	}

	tagSet := make(map[string]bool)
	for _, tag := range memoryTags {
		tagSet[tag] = true
	}

	for _, tag := range searchTags {
		if !tagSet[tag] {
			return false
		}
	}
	return true
}

// GetMemoryByID implements MemoryManager
func (m *BaseMemoryManager) GetMemoryByID(id string) Memory {
	return &BaseMemory{
		manager: m,
		id:      id,
	}
}
